#pragma once
#include<fstream>
#include<vector>
#include <algorithm>
#include <sstream>
#include"Socket.hpp"
#include"Log.hpp"
#include<pthread.h>
#include <unordered_map>

using namespace std;
const string wwwroot="./wwwroot"; // web 根目录
const string sep = "\r\n";
const string homepage = "index.html";
class HttpServe;
class ThreadData
{
public:
    ThreadData(int sockfd,HttpServe*t):sockfd_(sockfd),ts(t)
    {
    }
    int Getsockfd()
    {
        return sockfd_;
    }
    ~ThreadData()
    {
    }
public:
    int sockfd_;
    HttpServe *ts;
};
class HttpRequest//7协议
{
public:
    HttpRequest()
    {
    }
    void Deserialize(string buffer)
    {
        while(true)
        {
        size_t pos=buffer.find(sep);
        if(pos==std::string::npos) break;
        string s=buffer.substr(0,pos);
        if(s.empty()) break;
        reqheader.push_back(s);
        buffer.erase(0,pos+sep.size());
        }
        text=buffer;
    }
    void Parse()
    {
        stringstream ss(reqheader[0]);//以空格分开字符串
        ss>>method>>url>>http_version;
        std::cout << "method: " << method << std::endl;
        std::cout << "url: " << url << std::endl;
        std::cout << "http_version: " << http_version << std::endl;
        file_path = wwwroot; // ./wwwroot
        if(url == "/" || url == "/index.html") 
        {
            file_path += "/";
            file_path += homepage; // ./wwwroot/index.html
        }
        else file_path+=url;// /a/b/c/d.html->./wwwroot/a/b/c/d.html
        cout<<"file_path: "<<file_path<<endl;
        auto pos=file_path.find(".");
        if(pos==std::string::npos) suffix="html";
        else suffix=file_path.substr(pos);
    }
    ~ HttpRequest()
    {
    }
public:
    vector<string> reqheader;
    string text;

    string method;
    string url;
    string http_version;
    string file_path;

    string suffix;//类型.html还是图片
};
class HttpServe
{
public:
    HttpServe(uint16_t port):port_(port)
    {
        content_type.insert({".html", "text/html"});
        content_type.insert({".png", "image/png"});
    }
    void Init()//1
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        lg(Info, "Init done");
    }
    void Start()//2
    {
        while(true)
        {
        string clientip;
        uint16_t clientport;
        int sockfd=listensock_.Accept(clientip,clientport);//通信套接字
        if(sockfd<0) continue;
        lg(Info, "get a new connect, sockfd: %d", sockfd);
        char buffer[1024];
        pthread_t tid;
        ThreadData* td=new ThreadData(sockfd,this);
        pthread_create(&tid,nullptr,Run,td);
        }
    }
    static void*Run(void *args)//3，必须静态不然返回this指针
    {
        pthread_detach(pthread_self());//线程分离v
        ThreadData *td=static_cast<ThreadData*>(args);
        td->ts->HandlerHttp(td->Getsockfd());
        return nullptr;
    }
     string Readhtml(const string &htmlpath)//5
    {
        std::ifstream in(htmlpath, std::ios::binary);
        if(!in.is_open()) return "";

        in.seekg(0, std::ios_base::end);
        auto len = in.tellg();
        in.seekg(0, std::ios_base::beg);

        std::string content;
        content.resize(len);

        in.read((char*)content.c_str(), content.size());
        // std::ifstream in(htmlpath);
        // if(!in.is_open()) return "404";

        // std::string content;
        // std::string line;
        // while(std::getline(in, line))
        // {
        //     content += line;
        // }
  
        // in.close();
        in.close();
        return content;
    }
    string SuffixToDesc(const std::string &suffix)
    {
        auto iter = content_type.find(suffix);
        if(iter == content_type.end()) return content_type[".html"];
        else return content_type[suffix];
    }
    void HandlerHttp(int sockfd)//4
    {
        char buffer[10240];
        ssize_t n=recv(sockfd,buffer,sizeof(buffer),0);
        if(n>0)
        {
            buffer[n]=0;
            cout<<buffer<<endl;//假设独到的完整http响应
            HttpRequest req;
            req.Deserialize(buffer);
            req.Parse();

            //回应
            bool cmz=true;
            string text=Readhtml(req.file_path);//6
            if(text.empty())
            {
                cmz=false;
                string err_html = wwwroot;
                err_html += "/";
                err_html += "err.html";
                text = Readhtml(err_html);
            }

            string response_line;
            if(cmz)
                response_line = "HTTP/1.0 200 OK\r\n";
            else
                response_line = "HTTP/1.0 404 Not Found\r\n";
            string response_header="Content-Length: ";
            response_header+=to_string(text.size());
            response_header+="\r\n";
            response_header += "Content-Type: ";
            response_header += SuffixToDesc(req.suffix);//7判断类型函数
            response_header += "\r\n";
            response_header += "Set-Cookie: name=haha&&passwd=12345";//8存储信息
            response_header += "\r\n";
            string blank_line="\r\n";
            string response=response_line;
            response+=response_header;
            response+=blank_line;
            response+=text;
            send(sockfd,response.c_str(),response.size(),0);
        }
        close(sockfd);
    }
    ~HttpServe()
    {

    }
private:
    Sock listensock_;
    uint16_t port_;
    std::unordered_map<std::string , std::string> content_type;
};